package api

import (
	"github.com/ahmetb/go-linq/v3"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"hcy-api/lib/http"
	"hcy-api/lib/id"
	"hcy-api/structs/enum"
	"hcy-api/structs/sys"
	"hcy-api/structs/tables"
	"sys/global"
	repository2 "sys/module/dao"
	"sys/module/service"
	"time"
)

var OrgApi = new(orgApi)

type orgApi struct {
}

func (a orgApi) Create(c *gin.Context) {
	var in sys.AddOrg
	if err := c.ShouldBindJSON(&in); err != nil {
		http.BadWithParamsError(c, err)
		return
	}
	self := http.GetCurrentUser(c)
	b, err := repository2.OrgRepository.CheckIsExist(in.ParentId, in.OrgName)
	if err != nil {
		http.BadWithDB(c, err)
		return
	}
	if b {
		http.BadWithCode(c, enum.ErrorMap.OrgNameIsExist)
		return
	}
	t := &tables.Org{
		Id:       id.GetSnowId(),
		ParentId: in.ParentId,
		OrgName:  in.OrgName,
		Status:   in.Status,
		AutoCreateInfo: tables.AutoCreateInfo{
			Creator:   self.Nickname,
			CreatorId: self.UserID,
			CreatedAt: time.Now().Unix(),
			UpdatedAt: 0,
			DeletedAt: 0,
		},
	}
	err = global.DB.Transaction(func(tx *gorm.DB) error {
		err = tx.Create(&t).Error
		if err != nil {
			return err
		}
		m1 := &tables.MapUserOrg{
			UserId: self.UserID,
			OrgId:  t.Id,
		}
		m2 := &tables.MapUserOrg{
			UserId: tables.RootId,
			OrgId:  t.Id,
		}
		ms := make([]*tables.MapUserOrg, 0)
		ms = append(ms, m1)
		ms = append(ms, m2)
		err = tx.CreateInBatches(ms, len(ms)).Error
		return err
	})
	if err != nil {
		http.BadWithDB(c, err)
		return
	}
	http.OK204(c)
}

func (a orgApi) List(c *gin.Context) {
	self := http.GetCurrentUser(c)
	li, err := service.OrgService.GetSubList(self.OrgId)
	if err != nil {
		http.BadWithDB(c, err)
		return
	}
	li2, err := repository2.UserDB.FindOrgListByUserId(self.UserID)
	if err != nil {
		http.BadWithDB(c, err)
		return
	}
	for _, v := range li2 {
		li = append(li, sys.OrgNode{
			Id:       v.Id,
			OrgName:  v.OrgName,
			ParentId: v.ParentId,
			Mate:     v,
			Children: nil,
		})
	}
	linq.From(li).DistinctBy(func(i interface{}) interface{} {
		return i.(sys.OrgNode).Id
	}).ToSlice(&li)
	http.Ok(c, li)
}

func (a orgApi) All(c *gin.Context) {
	self := http.GetCurrentUser(c)
	li, err := repository2.UserDB.FindOrgListByUserId(self.UserID)
	if err != nil {
		http.BadWithDB(c, err)
		return
	}
	http.Ok(c, li)
}

func (a orgApi) UserList(c *gin.Context) {
	in := struct {
		OrgId int64 `uri:"orgId"`
	}{}
	if err := c.ShouldBindUri(&in); err != nil {
		http.BadWithParamsError(c, err)
		return
	}
	li, err := repository2.OrgRepository.FindUserList(in.OrgId)
	if err != nil {
		http.BadWithDB(c, err)
		return
	}
	http.Ok(c, li)
}

func (a orgApi) Delete(c *gin.Context) {
	in := struct {
		Id int64 `uri:"id"`
	}{}
	if err := c.ShouldBindUri(&in); err != nil {
		http.BadWithParamsError(c, err)
		return
	}
	org, err := repository2.OrgRepository.FindById(in.Id)
	if err != nil {
		http.BadWithDB(c, err)
		return
	}
	self := http.GetCurrentUser(c)
	if org.CreatorId != self.UserID {
		http.BadWithCode(c, enum.ErrorMap.AccessDeniedForCreate)
		return
	}
	err = global.DB.Transaction(func(tx *gorm.DB) error {
		err = tx.Where(&tables.Org{Id: in.Id}).Delete(&tables.Org{}).Error
		if err != nil {
			return err
		}
		err = tx.Where(&tables.MapUserOrg{OrgId: in.Id}).Delete(&tables.MapUserOrg{}).Error
		return err
	})
	if err != nil {
		http.BadWithDB(c, err)
		return
	}
	http.OK204(c)
}
